<template>
  <div
    class="E-lyric no-scroll-bar"
    v-loading="load"
    element-loading-text="拼命加载中..."
    element-loading-spinner="el-icon-loading"
  >
    <ul
      class="lyric-list no-scroll-bar"
      v-if="lines.length"
      :style="{
      maxHeight:expand?'unset':'100px'
    }"
      v-roll
    >
      <li :class="{sign:sign(item)}" v-for="(item, index) in lines" :key="index">{{item}}</li>
    </ul>
    <p class="no-data" v-else>暂无数据</p>
    <div class="wrap-btn">
      <el-button
        size="mini"
        v-clipboard:copy="lines.join('\n')"
        v-clipboard:success="onCopy"
        v-clipboard:error="onError"
        icon="fa fa-clipboard"
        circle
      ></el-button>
      <el-button size="mini" @click="listFocus()" icon="el-icon-location" circle></el-button>
      <el-button
        size="mini"
        @click="expand=!expand"
        :icon="`fa ${expand?'fa-compress':'fa-expand'}`"
        circle
      ></el-button>
    </div>
  </div>
</template>

<script>
import Lyric from 'lyric-parser';

export default {
  props: ['id', 'keywords'],
  mounted() {
    this.getData(this.id);
  },
  data() {
    return {
      load: false,
      lyric: '',
      currentLyric: {},
      currentLineNum: 0,
      lines: [],
      expand: false,
      lrcEl: null,
      timer: null
    };
  },
  methods: {
    getData(id) {
      this.load = true;
      this.$api.get('music_lyric', { id }, true).then(({ lrc: { lyric } }) => {
        this.lyric = lyric;
        this.currentLyric = new Lyric(lyric, this.handleLyric);
        setTimeout(() => {
          const list = this.currentLyric.lines;
          if (list.length) {
            this.lines = list.map(({ txt }) => txt);
          } else {
            this.lines = lyric.split('\n');
          }
          this.listFocus();
        }, 0);
      }).finally(() => { this.load = false; });
    },
    sign(it) {
      return it.includes(this.keywords);
    },
    listFocus() {
      setTimeout(() => {
        if (!this.lrcEl) return;
        const dom = this.lrcEl.querySelector('.sign');
        if (!dom) return;
        const { top: basicsTop } = this.lrcEl.getBoundingClientRect();
        const rectDom = dom.getBoundingClientRect();
        let scrollTop = (rectDom.top - basicsTop);
        scrollTop -= (rectDom.height * 2);
        // 兼容
        if (this.lrcEl.scrollTo) {
          this.lrcEl.scrollTo({ top: scrollTop, behavior: 'smooth' });
        } else {
          this.bufferSports(this.lrcEl, scrollTop);
        }
      }, 0);
    },
    // 平滑滚动
    bufferSports(event, locY = 0, speed = 7) {
      clearInterval(this.timer);
      let top = null;
      this.timer = setInterval(() => {
        const cur = event.scrollTop;
        let spY = (locY - cur) / speed;
        spY = spY > 0 ? Math.ceil(spY) : Math.floor(spY);
        // 判断是否能继续滚动，如果无法滚动就结束。两种情况会导致无法滚动。locY<0 or locY超出高度。
        top = top !== cur + spY ? cur + spY : locY;
        if (locY - top === 0) {
          clearInterval(this.timer);
          // eslint-disable-next-line no-param-reassign
          event.scrollTop = top;
        } else {
          // eslint-disable-next-line no-param-reassign
          event.scrollTop = top;
        }
      }, 30);
    },
    onCopy(e) {
      this.$message({
        showClose: true,
        type: 'success',
        message: 'Copy 成功'
      });
    },
    onError(e) {
      this.$message({
        showClose: true,
        type: 'error',
        message: 'Copy 失败'
      });
    }
  },
  directives: {
    roll: {
      bind(el, bindings, vnode) {
        // eslint-disable-next-line no-underscore-dangle
        const _this = vnode.context;
        _this.lrcEl = el;
      }
    }
  }
};
</script>

<style lang="scss" scoped>
.E-lyric {
  position: relative;
  & > .lyric-list {
    font-size: 15px;
    max-width: 400px;
    line-height: 20px;
    text-align: center;
    overflow: hidden;
    overflow-y: scroll;
    & > li {
      &.sign {
        color: rgb(240, 99, 99);
      }
    }
  }
  & > .no-data {
    text-align: center;
    font-size: 16px;
    color: #ccc;
    line-height: 100px;
  }
  & > .wrap-btn {
    position: absolute;
    top: 0;
    right: 0;
  }
}
</style>
